/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { findIndex } from 'lodash';
import classnames from 'classnames';
import {
  Button,
  Callout,
  Classes,
  Dialog,
  FormGroup,
  InputGroup,
  Intent,
  Position
} from '@blueprintjs/core';
import { FormValidation } from 'calidation';

// Services
import { SchemaService } from '../../../../../services';

// Utils
import { Saiku } from '../../../../../utils';

class AddSchemaDialog extends Component {
  constructor(props) {
    super(props);

    this.state = {
      fileInputValue: 'Choose file...',
      file: null,
      isInvalidExtension: false,
      isInvalidSchemaName: false,
      loading: false
    };

    this.formValidationConfig = {
      schemaName: {
        isRequired: 'Schema Name field is required'
      },
      fileSchema: {
        isRequired: 'Upload Schema field is required'
      }
    };
  }

  checkFileExtension(filename) {
    if (!filename) {
      return '';
    }

    const [ext] = /[^./\\]*$/.exec(filename) || [''];

    return ext.toLowerCase();
  }

  onChangeFile = event => {
    const { files } = event.target;
    const fileInputValue = event.target.value;

    this.setState(
      {
        fileInputValue
      },
      () => {
        if (this.checkFileExtension(fileInputValue) === 'xml') {
          this.setState({ file: files[0], isInvalidExtension: false });
        } else {
          this.setState({ isInvalidExtension: true });
        }
      }
    );
  };

  handleSubmit = ({ fields, errors, isValid }) => {
    if (isValid) {
      const { getSchemas, onClose } = this.props;
      const { file } = this.state;
      const { schemaName } = fields;

      this.setState({ loading: true });

      SchemaService.getSchemas()
        .then(res => {
          if (res.status === 200) {
            const hasXmlExtension = schemaName.includes('.xml');
            const schemaNameToCheck = hasXmlExtension
              ? schemaName.split('.xml')[0]
              : schemaName;
            const schemaIndex = findIndex(res.data, {
              name: `${schemaNameToCheck}.xml`
            });

            if (schemaIndex !== -1) {
              this.setState({
                isInvalidSchemaName: true,
                loading: false
              });
            } else {
              SchemaService.postSchemaFile(file, schemaName)
                .then(res => {
                  this.setState({ loading: false });

                  if (res.status === 200) {
                    Saiku.toasts(Position.TOP_RIGHT).show({
                      icon: 'tick',
                      intent: Intent.SUCCESS,
                      message: 'Upload Successful'
                    });

                    getSchemas();
                    onClose();
                  } else {
                    Saiku.toasts(Position.TOP_RIGHT).show({
                      icon: 'error',
                      intent: Intent.DANGER,
                      message: 'Upload failed'
                    });
                  }
                })
                .catch(error => {
                  Saiku.toasts(Position.TOP_RIGHT).show({
                    icon: 'error',
                    intent: Intent.DANGER,
                    message: 'Upload failed'
                  });
                });
            }
          } else {
            this.setState({ loading: false });
            Saiku.toasts(Position.TOP_RIGHT).show({
              icon: 'error',
              intent: Intent.DANGER,
              message: 'Something went wrong'
            });
          }
        })
        .catch(error => {
          this.setState({ loading: false });
          Saiku.toasts(Position.TOP_RIGHT).show({
            icon: 'error',
            intent: Intent.DANGER,
            message: 'Something went wrong'
          });
        });
    }
  };

  renderErrorInvalidExtension() {
    return (
      <Callout
        className="m-b-20"
        intent={Intent.DANGER}
        style={{ color: '#ee5342' }}
      >
        Invalid file! You must upload a valid XML schema!
      </Callout>
    );
  }

  renderErrorInvalidSchemaName() {
    return (
      <Callout
        className="m-b-20"
        intent={Intent.DANGER}
        style={{ color: '#ee5342' }}
      >
        The schema name already exists! Enter another name...
      </Callout>
    );
  }

  renderForm() {
    const { onClose } = this.props;
    const {
      fileInputValue,
      isInvalidExtension,
      isInvalidSchemaName,
      loading
    } = this.state;

    return (
      <FormValidation
        onSubmit={this.handleSubmit}
        config={this.formValidationConfig}
        style={{ margin: 0 }}
      >
        {({ fields, errors, submitted }) => (
          <Fragment>
            <div className={Classes.DIALOG_BODY}>
              {isInvalidExtension && this.renderErrorInvalidExtension()}
              {isInvalidSchemaName && this.renderErrorInvalidSchemaName()}

              <FormGroup
                label="Schema Name"
                labelFor="schemaName"
                intent={
                  submitted && errors.schemaName ? Intent.DANGER : Intent.NONE
                }
                helperText={
                  submitted && errors.schemaName ? errors.schemaName : ''
                }
              >
                <InputGroup
                  name="schemaName"
                  intent={
                    submitted && errors.schemaName ? Intent.DANGER : Intent.NONE
                  }
                  autoFocus
                />
              </FormGroup>
              <FormGroup
                label="Upload Schema"
                labelFor="fileSchema"
                intent={
                  submitted && errors.fileSchema ? Intent.DANGER : Intent.NONE
                }
                helperText={
                  submitted && errors.fileSchema ? errors.fileSchema : ''
                }
              >
                <label className="bp3-file-input bp3-fill">
                  <input
                    className="bp3-input bp3-fill"
                    type="file"
                    name="fileSchema"
                    onChange={this.onChangeFile}
                  />
                  <span
                    className={classnames('bp3-input bp3-file-upload-input', {
                      'bp3-intent-danger': submitted && errors.fileSchema
                    })}
                  >
                    {fileInputValue}
                  </span>
                </label>
              </FormGroup>
            </div>
            <div className={Classes.DIALOG_FOOTER}>
              <div className={Classes.DIALOG_FOOTER_ACTIONS}>
                <Button
                  type="submit"
                  text="Add"
                  intent={Intent.DANGER}
                  loading={loading}
                  disabled={isInvalidExtension}
                />
                <Button text="Close" onClick={onClose} />
              </div>
            </div>
          </Fragment>
        )}
      </FormValidation>
    );
  }

  render() {
    const { onClose } = this.props;

    return (
      <Dialog
        title="Add Schema"
        icon="plus"
        canOutsideClickClose={false}
        isOpen={true}
        onClose={onClose}
      >
        {this.renderForm()}
      </Dialog>
    );
  }
}

AddSchemaDialog.propTypes = {
  getSchemas: PropTypes.func.isRequired,
  onClose: PropTypes.func.isRequired
};

export default AddSchemaDialog;
